package net.xuele.learn.IO.fakeAio;

import net.xuele.learn.IO.bio.TimeServerHandler;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Created by GaoQingming on 2019/4/10 0010.
 * 使用线程池，避免了每线程每连接的问题，但是它仍旧是bio！
 *
 * 问题在于：socket使用输入流进行读取操作的时候，它会一直阻塞，直到——
 *          1、有数据可读
 *          2、可用数据读取完毕
 *          3、出现了异常
 *
 *          而调用输出流的write方法的时候，它将会被阻塞，直到要发送的消息全部发送完毕，或者发生异常。
 *          基于TCP进行通信的时候，当消息的接收方处理消息的速度过慢时，将不能及时的从TCP缓冲区读取数据，
 *          这将会导致发送方的window size不断减小，直到为0.双方保持keep-alive状态，发送方将不再向TCP缓冲区写入消息，
 *          如果是阻塞式IO，write操作将被无限期阻塞（无法向缓冲区写入数据！），直到TCP的window size大于0或者发送IO异常
 *
 *  也就是说，读和写的过程都需要阻塞！
 *
 */
public class Timeserver {
    public static void main(String[] args) throws IOException {
        int port = 7777;
        ServerSocket serverSocket = null;
        try {
            // 这一步调用了socket函数、bind函数和listen函数
            serverSocket = new ServerSocket(port);
            System.out.println("the server start at port"+port);
            Socket socket = null;
            // 利用这个线程池，就避免了每连接每线程的问题了
            TimeServerHandlerExecutorPool executor = new TimeServerHandlerExecutorPool(10,1000);
            // 无限循环监听客户端连接
            while (true) {
                // 这一步是阻塞的，如果没有客户端连接，主线程将阻塞在这里；
                // 线程被阻塞意味着这个线程无法进行其他的操作，对于操作系统来说，会有唤醒线程的消耗
                // 这一步最终调用了accept函数
                socket = serverSocket.accept();
                // 接收到连接，就进行具体业务的处理，也就是读取发送过来的消息
                executor.execute(new TimeServerHandler(socket));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (serverSocket != null) {
                System.out.println("the server is closed!");
                serverSocket.close();
                serverSocket = null;
            }
        }
    }
}
